package com.example.demo.util;

import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Proxy.Type;
import java.net.URL;
import java.net.URLEncoder;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Map.Entry;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HttpClientUtil {
	private static final Logger logger = LoggerFactory.getLogger(HttpClientUtil.class);
	protected static final int SOCKET_TIMEOUT = 3000; // 3S

	public enum Method {
		GET, POST
	}

	private static TrustManager myX509TrustManager = new X509TrustManager() {

		@Override
		public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
			// Do nothing because of X and Y.
		}

		@Override
		public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
			// Do nothing because of X and Y.
		}

		@Override
		public X509Certificate[] getAcceptedIssuers() {
			return null;
		}
	};

	public static String requestUrl(String host, Map<String, String> params, Method method, Map<String, String> headers,
			InetSocketAddress inetSocketAddress) {
		try {
			// 设置SSLContext
			SSLContext sslcontext = SSLContext.getInstance("TLS");
			sslcontext.init(null, new TrustManager[] { myX509TrustManager }, null);

			String sendUrl = getUrlWithQueryString(host, params);
			logger.info("sendUrl:{}", sendUrl);
			URL uri = new URL(sendUrl); // 创建URL对象

			HttpURLConnection conn;
			if (inetSocketAddress != null) {
				Proxy proxy = new Proxy(Type.HTTP, inetSocketAddress);
				conn = (HttpURLConnection) uri.openConnection(proxy);
			} else {
				conn = (HttpURLConnection) uri.openConnection();
			}
			if (conn instanceof HttpsURLConnection) {
				((HttpsURLConnection) conn).setSSLSocketFactory(sslcontext.getSocketFactory());
			}
			if (headers != null) {
				for (Entry<String, String> entry : headers.entrySet()) {
					String key = entry.getKey();
					String value = entry.getValue();
					conn.addRequestProperty(key, value);
				}
			}
			conn.setConnectTimeout(SOCKET_TIMEOUT); // 设置相应超时
			conn.setRequestMethod(method.toString());
			int statusCode = conn.getResponseCode();
			if (statusCode != HttpURLConnection.HTTP_OK) {
				logger.error("错误码：{}", statusCode);
				return null;
			}

			// 读取服务器的数据
			InputStream is = conn.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(is, "utf-8"));
			StringBuilder builder = new StringBuilder();
			String line;
			while ((line = br.readLine()) != null) {
				builder.append(line);
			}

			String text = builder.toString();

			close(br); // 关闭数据流
			close(is); // 关闭数据流
			conn.disconnect(); // 断开连接
			logger.info("{}请求返回:{}", sendUrl, text);
			return text;
		} catch (Exception e) {
			logger.error("http请求失败！", e);
		}

		return null;
	}

	private static String getUrlWithQueryString(String url, Map<String, String> params) {
		if (params == null) {
			return url;
		}

		StringBuilder builder = new StringBuilder(url);
		if (url.contains("?")) {
			builder.append("&");
		} else {
			builder.append("?");
		}

		int i = 0;
		for (Entry<String, String> entry : params.entrySet()) {
			String key = entry.getKey();
			String value = entry.getValue();
			if (value == null) { // 过滤空的key
				continue;
			}

			if (i != 0) {
				builder.append('&');
			}

			builder.append(key);
			builder.append('=');
			builder.append(encode(value));

			i++;
		}

		return builder.toString();
	}

	protected static void close(Closeable closeable) {
		if (closeable != null) {
			try {
				closeable.close();
			} catch (IOException e) {
				logger.error("http关闭失败！", e);
			}
		}
	}

	/**
	 * 对输入的字符串进行URL编码, 即转换为%20这种形式
	 * 
	 * @param input
	 *            原文
	 * @return URL编码. 如果编码失败, 则返回原文
	 */
	public static String encode(String input) {
		if (input == null) {
			return "";
		}

		try {
			return URLEncoder.encode(input, "utf-8");
		} catch (UnsupportedEncodingException e) {
			logger.error("encode编码失败！", e);
		}

		return input;
	}

}
